import asyncio
import struct
from bleak import BleakScanner, BleakClient
from datetime import datetime

# Указываем ID устройства для поиска
target_service_id = "2555a4bf-3b77-4603-9089-49db2ecba11a"
target_attr_id = "bc0bb800-5225-4a59-9668-7cc7c0c51821"

class OnData:
    def __init__(self):
        self.freq = 0

        # Данные батареи блока
        self.battery_current = 0
        self.battery_voltage = 0
        self.battery_percent = 0

        self.gyro_x = 0
        self.gyro_y = 0
        self.gyro_z = 0

        self.sdf = '%H:%M:%S.%f'

        self.emg = [0] * 8
        self.alfa = 0.01
        self.mean = [0.0] * 8
        self.ch_offset = [0] * 8
        self.ch_coef = [1] * 8

        self.settings_sync = asyncio.Lock()

    def decode_data(self, data):
        if len(data) < 20:
            print("Недостаточно данных")
            return

        self.freq += 2
        indb = (data[0] >> 4) % 4
        if indb == 3:  # Декодируем пакет
            self.battery_current = data[2] * 2  # Ток модуля
            self.battery_voltage = (((data[1] & 0xFF) * 2 + 1230) * 2.44) - (25 if self.battery_current > 0 else 0)  # Напряжение батареи

            # Вычисляем процент заряда
            if self.battery_voltage < 3400:
                self.battery_percent = 0
            elif self.battery_voltage > 4100:
                self.battery_percent = 100
            else:
                self.battery_percent = (self.battery_voltage - 3400) / 7

            print(f"Battery current: {self.battery_current}, voltage: {self.battery_voltage}, percent: {self.battery_percent}")

        else:
            gyro = (data[1] & 0xFF) | (data[2] << 8)
            if indb == 0:
                self.gyro_x = gyro
            elif indb == 1:
                self.gyro_y = gyro
            elif indb == 2:
                self.gyro_z = gyro
            print(f"Gyro data - x: {self.gyro_x}, y: {self.gyro_y}, z: {self.gyro_z}")

        date = datetime.now()
        timestamp = date.strftime(self.sdf)[:-3]
        file_buff = f"timestamp: {timestamp}\n"

        for i in range(2):
            for j in range(8):
                if i == ((data[0] >> 3) & 0x01) and (data[0] & 0x07) == j:
                    self.emg[j] = (data[3] & 0xff) + (data[4 + i * 8 + j] & 0xff) * 256
                else:
                    self.emg[j] -= data[4 + i * 8 + j]
                self.mean[j] = self.emg[j] * self.alfa + self.mean[j] * (1 - self.alfa)
                file_buff += f"emg{j+1}: {self.emg[j]}\n"

        file_buff += f"gyro_x: {self.gyro_x}\ngyro_y: {self.gyro_y}\ngyro_z: {self.gyro_z}\n"

        print(f"Полученные данные:\n{file_buff}")

    async def notification_handler(self, sender, data):
        async with self.settings_sync:
            self.decode_data(data)

    async def scan_and_connect(self):
        devices = await BleakScanner.discover()
        for device in devices:
            async with BleakClient(device.address) as client:
                services = await client.get_services()
                for service in services:
                    if service.uuid == target_service_id:
                        print(f"Найдено устройство с Service ID: {target_service_id}")
                        for characteristic in service.characteristics:
                            if characteristic.uuid == target_attr_id:
                                print(f"Найдено устройство с Attribute ID: {target_attr_id}")
                                await client.start_notify(characteristic.uuid, self.notification_handler)
                                await asyncio.sleep(30)  # Ожидание получения данных в течение 30 секунд
                                await client.stop_notify(characteristic.uuid)
                                return True
        print("Устройство не найдено.")
        return False

# Запуск асинхронного сканирования и получения данных
on_data_instance = OnData()
asyncio.run(on_data_instance.scan_and_connect())